#include "media_frame.h"

#include <map>
#include <string.h>
#include <ctime>

#include "base_memory_pool.h"
#include "base_utils.h"
#include "base_log.h"

namespace El {
namespace Media {

MediaFrame::~MediaFrame()
{
    // 释放内存池分配的内存
    if (poolData_ != nullptr) {
        Base::MemoryPool::GetInstance().Free(poolData_);
        poolData_ = nullptr;
        poolDataSize_ = 0;
    }
}

void MediaFrame::SetUsePool(bool use_pool)
{
    use_pool_ = use_pool;
}

bool MediaFrame::PutBuffer(const uint8_t *data, int32_t length)
{
    if (!use_pool_) {
        return buf_.PutBuffer(data, length);
    }

    // 使用内存池分配内存
    if (poolData_ != nullptr) {
        // 如果已经有分配的内存，先释放
        Base::MemoryPool::GetInstance().Free(poolData_);
        poolData_ = nullptr;
        poolDataSize_ = 0;
    }

    // 从内存池分配新内存
    poolData_ = Base::MemoryPool::GetInstance().Allocate(length);
    if (poolData_ == nullptr) {
        LOG_DEBUG("MediaFrame: Failed to allocate memory from pool, size: {}", length);
        return false;
    }

    // 记录分配的大小
    poolDataSize_ = length;

    // 复制数据
    memcpy(poolData_, data, length);
    return true;
}

uint8_t *MediaFrame::GetBuffer() const
{
    if (!use_pool_) {
        return buf_.GetBuffer();
    }
    return static_cast<uint8_t *>(poolData_);
}

int32_t MediaFrame::GetLength() const
{
    if (!use_pool_) {
        return buf_.GetLength();
    }

    return poolDataSize_;
}

void MediaFrame::SetChannel(int32_t channel)
{
    ch_ = channel;
}

int32_t MediaFrame::GetChannel() const
{
    return ch_;
}

void MediaFrame::SetFrameType(uint32_t type)
{
    type_ = type;
}

uint32_t MediaFrame::GetFrameType() const
{
    return type_;
}

uint64_t MediaFrame::GetPts() const
{
    return pts_;
}

void MediaFrame::SetPts(uint64_t pts)
{
    pts_ = pts;
}

uint64_t MediaFrame::GetUtc() const
{
    return utc_;
}

void MediaFrame::SetUtc(uint64_t utc)
{
    utc_ = utc;
}

void MediaFrame::SetSeq(uint32_t seq)
{
    seq_ = seq;
}

uint32_t MediaFrame::GetSeq() const
{
    return seq_;
}

void MediaFrame::SetFrameRate(double frame_rate)
{
    frame_rate_ = frame_rate;
}

double MediaFrame::GetFrameRate() const
{
    return frame_rate_;
}

void MediaFrame::SetCodecType(uint32_t type)
{
    codec_type_ = type;
}

uint32_t MediaFrame::GetCodecType() const
{
    return codec_type_;
}

bool MediaFrame::IsVideoFrame() const
{
    return codec_type_ == MEDIA_VIDEO_CODEC_H264 || codec_type_ == MEDIA_VIDEO_CODEC_H265;
}

bool MediaFrame::IsAudioFrame() const
{
    return codec_type_ == MEDIA_AUDIO_CODEC_AAC || codec_type_ == MEDIA_AUDIO_CODEC_G711A ||
           codec_type_ == MEDIA_AUDIO_CODEC_G711U;
}

std::string MediaFrame::ToString() const
{
    const static std::map<int32_t, std::string> g_frameString = {
        {MEDIA_FRAME_UNKOWN, "UNKOWN"}, // 未知类型
        {MEDIA_FRAME_I, "I"},           // I帧
        {MEDIA_FRAME_P, "P"},           // P帧
        {MEDIA_FRAME_B, "B"},           // B帧
        {MEDIA_FRAME_MJPEG, "MJPEG"},   // MJPEG帧
        {MEDIA_FRAME_JPEG, "JPEG"},     // JPEG帧
        {MEDIA_FRAME_PCM, "PCM"},       // 原始音频帧
        {MEDIA_FRAME_AAC, "AAC"},       // AAC音频帧
        {MEDIA_FRAME_G711A, "G711A"},   // G711A音频帧
        {MEDIA_FRAME_G711U, "G711U"},   // G711U音频帧
    };

    return std::string("MediaFrame(")
        .append("ch:")
        .append(std::to_string(ch_))
        .append(" utc:")
        .append(Base::utcToString(utc_))
        .append(" pts:")
        .append(std::to_string(pts_))
        .append(" seq:")
        .append(std::to_string(seq_))
        .append(" type:")
        .append(g_frameString.find(type_)->second)
        .append(" len:")
        .append(std::to_string(GetLength()))
        .append(")");
}

} // namespace Media
} // namespace El